package com.game.framework.common.utils;

import com.google.common.collect.Lists;

import java.util.*;

/**
 * 随机数工具
 */
public class RandomUtil {

  private static final Random random = new Random();

  /**
   * 取得随机
   */
  public static int random(int num) {
    return random.nextInt(num);
  }

  /**
   * 浮点数随机数
   */
  public static double randomDouble(final double min, final double max) {
    return min + ((max - min) * new Random().nextDouble());
  }

  /**
   * 区间内的随机数
   */
  public static int randomInt(int min, int max) {
    int end = max - min;
    if (end <= 0) {
      System.out.println("j");
    }
    return min + random.nextInt(end);
  }

  /**
   * 范围内，取得不重复的N个随机数
   */
  public static int[] randomNumber(int max, int n) {
    return randomNumber(0, max, n);
  }
  /**
   * 范围内，取得不重复的N个随机数
   */
  public static int[] randomNumber(int min, int max, int n) {
    // 判断是否已经达到索要输出随机数的个数
    if (n > (max - min + 1) || max < min) {
      return null;
    }

    int[] result = new int[n];

    int count = 0;
    while (count < n) {
      int num = (int) (Math.random() * (max - min)) + min;
      boolean flag = true;
      for (int j = 0; j < count; j++) {
        if (num == result[j]) {
          flag = false;
          break;
        }
      }
      if (flag) {
        result[count] = num;
        count++;
      }
    }
    return result;
  }

  /**
   * 获取一个范围内的随机值
   *
   * @param randomMin 区间起始值
   * @param randomMax 区间结束值
   * @return 返回区间的一个随机值
   */
  public static int nextInt(int randomMin, int randomMax) {
    int randomBase = randomMax - randomMin;
    if (randomBase < 0) {
      throw new IllegalArgumentException("randomMax must be bigger than randomMin");
    } else if (randomBase == 0) {
      return randomMin;
    } else {
      return (random.nextInt(randomBase) + randomMin);
    }
  }

  /**
   * 从队列的前limit个对象中随机num个对象
   */
  public static <T> List<T> randomList(List<T> list, int limit, int num) {
    return randomList(list, 0, limit, num);
  }

  /**
   * 从数组的前limit个对象中随机num个对象
   *
   * @param num
   * @return
   */
  public static <T> List<T> randomList(T[] list, int num) {
    return randomList(list, 0, list.length, num);
  }

  /**
   * 从数组的前limit个对象中随机num个对象
   */
  public static <T> List<T> randomList(T[] list, int min, int max, int num) {
    max = Math.min(list.length, max);
    int n = max - min;
    if (n < 1) {
      return null;
    }
    List<T> rlist = Lists.newArrayList();
    if (n <= num) {
      for (int i = min; i < max; i++) {
        rlist.add(list[i]);
      }
      return rlist;
    }

    n -= num;
    int step = 1 + (int) Math.ceil((double) n / num);

    int gostep = random.nextInt(step);
    int addStep = 0;
    for (int i = 0; i < num; i++) {
      addStep += gostep;
      if (addStep >= n) {
        addStep = n;
      }
      rlist.add(list[min + i + addStep]);

      gostep = random.nextInt(step);
    }

    return rlist;
  }

  /**
   * 从队列的前limit个对象中随机num个对象
   */
  public static <T> List<T> randomList(List<T> list, int min, int max, int num) {
    max = Math.min(list.size(), max);
    int n = max - min;
    if (n < 1) {
      return null;
    }
    List<T> rlist = Lists.newArrayList();
    if (n <= num) {
      for (int i = min; i < max; i++) {
        rlist.add(list.get(i));
      }
      return rlist;
    }

    n -= num;
    int step = 1 + (int) Math.ceil((double) n / num);

    int gostep = random.nextInt(step);
    int addStep = 0;
    for (int i = 0; i < num; i++) {
      addStep += gostep;
      if (addStep >= n) {
        addStep = n;
      }
      rlist.add(list.get(min + i + addStep));

      gostep = random.nextInt(step);
    }

    return rlist;
  }

  /**
   * 从队列中随机num个对象
   */
  public static <T> List<T> randomList(List<T> list, int num) {

    return randomList(list, 0, list.size(), num);
  }

  /**
   * 从集合中随机size个元素
   */
  public static <T> List<T> randomList(Collection<T> list, int num) {
    int n = list.size();
    List<T> rlist = Lists.newArrayList();
    if (n <= num) {
      rlist.addAll(list);
      return rlist;
    }
    n -= num;
    int step = 1 + (int) Math.ceil((double) n / num);
    Iterator<T> it = list.iterator();
    int gostep = random.nextInt(step);
    while (it.hasNext() && rlist.size() < num) {
      if (gostep > 0) {
        gostep--;
        n--;
        it.next();
        continue;
      }
      rlist.add(it.next());
      if (n > 0) {
        gostep = random.nextInt(step);
      }
    }
    return rlist;
  }

  /**
   * 根据某个数字获取随机数
   */
  public static int getRandom(int num) {
    if (num <= 0) {
      return 0;
    }
    return random.nextInt(num);
  }

  /**
   * 随机抽取数值，范围是(minNum～maxNum）
   */
  public static int getRandom(int minNum, int maxNum) {
    if (minNum > maxNum) {
      return -1;
    }
    return (int) (Math.random() * (maxNum - minNum + 1)) + minNum;
  }

  /**
   * 随机抽取num数值，范围是(minNum～maxNum）
   */
  public static List<Integer> getRandomNum(int minNum, int maxNum, int num) {
    List<Integer> list = new ArrayList<Integer>();
    if (minNum > maxNum - num) {
      return null;
    }
    while (list.size() < num) {
      int a = (int) (Math.random() * (maxNum - minNum + 1)) + minNum;
      if (!list.contains(a)) {
        list.add(a);
      }
    }
    return list;
  }

  /**
   * 在一定范围内获得指定不重复的数字(取值范围不能大于100)
   */
  public static int[] getRandomData(int getNum, int maxNum) {
    if (getNum <= 0 || maxNum <= 0) {
      return null;
    }

    int[] a = new int[getNum];
    int[] b = new int[maxNum];
    long time = System.currentTimeMillis();

    if (getNum > maxNum) {
      return null;
    }
    for (int i = 0; i < getNum; i++) {
      a[i] = random.nextInt(maxNum);
      if (b[a[i]] > 0) {
        i--;
      } else {
        b[a[i]] = 1;
      }
      if (System.currentTimeMillis() - time > 1000) { // 1秒超时
        return null;
      }
    }
    return a;
  }

  /**
   * 从map中随机取得一个key
   */
  public static int getRandomKeyFromMap(Map<Integer, Integer> map) {
    int rn = getRandom(map.size());
    int i = 0;
    for (int key : map.keySet()) {
      if (i == rn) {
        return key;
      }
      i++;
    }
    return 0;
  }

  /***
   * 计算权重总和
   */
  private static double getDoubleWeightSum(List<Double> weights) {
    double weightSum = 0;
    for (double weightValue : weights) {
      weightSum += weightValue;
    }
    return weightSum;
  }

  private static int getIntegerWeightSum(List<Integer> weights) {
    int weightSum = 0;
    for (int weightValue : weights) {
      weightSum += weightValue;
    }
    return weightSum;
  }
  /***
   * 权重数组
   * 返回数据
   */
  public static <T> T getDoubleWeightRandom(List<Double> weightList, List<T> itemsList) {
    int index = 0;
    double stepWeightSum = 0;
    double weightSum = getDoubleWeightSum(weightList);
    double r = Math.random();
    for (double weight : weightList) {
      // 如果随机数落在了权重区间则返回索引值
      if ((r >= stepWeightSum / weightSum) && (r < (stepWeightSum + weight) / weightSum)) {
        return itemsList.get(index);
      }
      // 计算下一次区间的权重开始值
      stepWeightSum += weight;
      index++;
    }
    return null;
  }

  public static <T> T getIntegerWeightRandom(List<Integer> weightList, List<T> itemsList) {
    int index = 0;
    int stepWeightSum = 0;
    int weightSum = getIntegerWeightSum(weightList);
    int r = RandomUtil.getRandom(weightSum);
    for (int weight : weightList) {
      // 如果随机数落在了权重区间则返回索引值
      if ((r >= stepWeightSum) && (r < stepWeightSum + weight)) {
        return itemsList.get(index);
      }
      // 计算下一次区间的权重开始值
      stepWeightSum += weight;
      index++;
    }
    return null;
  }
}
